﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using JavaSubstitutes;
using Sonar;

namespace Sprites
{
	public class Shell : Sprite
	{
		private static double GROUND_INERTIA = 0.89f;
		private static double AIR_INERTIA = 0.89f;

		private double runTime;
		private bool onGround = false;

		public int width = 4;
		public int height = 24;

		private LevelScene world;
		public int facing;

		public bool avoidCliffs = false;
		public int anim;

		public bool dead = false;
		private int deadTime = 0;
		public bool carried;


		public Shell(LevelScene world, double x, double y, int type)
		{
			sheet = Art.enemies;

			this.x = x;
			this.y = y;
			this.world = world;
			xPicO = 8;
			yPicO = 31;

			yPic = type;
			height = 12;
			facing = 0;
			wPic = 16;

			xPic = 4;
			yDelta = -5;
		}

		public override bool fireballCollideCheck(Fireball fireball)
		{
			if (deadTime != 0) return false;

			double xD = fireball.x - x;
			double yD = fireball.y - y;

			if (xD > -16 && xD < 16)
			{
				if (yD > -height && yD < fireball.height)
				{
					if (facing != 0) return true;

					world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1);

					xDelta = fireball.facing * 2;
					yDelta = -5;
					if (spriteTemplate != null) spriteTemplate.isDead = true;
					deadTime = 100;
					hPic = -hPic;
					yPicO = -yPicO + 16;
					return true;
				}
			}
			return false;
		}

		public override void collideCheck()
		{
			if (carried || dead || deadTime > 0) return;

			double xMarioD = world.mario.x - x;
			double yMarioD = world.mario.y - y;
			//double w = 16;
			if (xMarioD > -16 && xMarioD < 16)
			{
				if (yMarioD > -height && yMarioD < world.mario.height)
				{
					if (world.mario.yDelta > 0 && yMarioD <= 0 && (!world.mario.onGround || !world.mario.wasOnGround))
					{
						world.mario.stomp(this);
						if (facing != 0)
						{
							xDelta = 0;
							facing = 0;
						}
						else
						{
							facing = world.mario.facing;
						}
					}
					else
					{
						if (facing != 0)
						{
							world.mario.getHurt();
						}
						else
						{
							world.mario.kick(this);
							facing = world.mario.facing;
						}
					}
				}
			}
		}

		public override void move()
		{
			if (carried)
			{
				world.checkShellCollide(this);
				return;
			}

			if (deadTime > 0)
			{
				deadTime--;

				if (deadTime == 0)
				{
					deadTime = 1;
					for (int i = 0; i < 8; i++)
					{
						world.addSprite(new Sparkle((int)(x + RandomExtensions.random() * 16 - 8) + 4, (int)(y - RandomExtensions.random() * 8) + 4, (double)(RandomExtensions.random() * 2 - 1), (double)RandomExtensions.random() * -1, 0, 1, 5));
					}
					spriteContext.removeSprite(this);
				}

				x += xDelta;
				y += yDelta;
				yDelta *= 0.95f;
				yDelta += 1;

				return;
			}

			if (facing != 0) anim++;

			double sideWaysSpeed = 11f;
			//        double sideWaysSpeed = onGround ? 2.5f : 1.2f;

			if (xDelta > 2)
			{
				facing = 1;
			}
			if (xDelta < -2)
			{
				facing = -1;
			}

			xDelta = facing * sideWaysSpeed;

			if (facing != 0)
			{
				world.checkShellCollide(this);
			}

			xFlipPic = facing == -1;

			runTime += (Math.Abs(xDelta)) + 5;

			xPic = (anim / 2) % 4 + 3;



			if (!move(xDelta, 0))
			{
				world.sound.play(Art.samples[Art.SAMPLE_SHELL_BUMP], this, 1, 1, 1);

				facing = -facing;
			}
			onGround = false;
			move(0, yDelta);

			yDelta *= 0.85f;
			if (onGround)
			{
				xDelta *= GROUND_INERTIA;
			}
			else
			{
				xDelta *= AIR_INERTIA;
			}

			if (!onGround)
			{
				yDelta += 2;
			}
		}

		private bool move(double xa, double ya)
		{
			while (xa > 8)
			{
				if (!move(8, 0)) return false;
				xa -= 8;
			}
			while (xa < -8)
			{
				if (!move(-8, 0)) return false;
				xa += 8;
			}
			while (ya > 8)
			{
				if (!move(0, 8)) return false;
				ya -= 8;
			}
			while (ya < -8)
			{
				if (!move(0, -8)) return false;
				ya += 8;
			}

			bool collide = false;
			if (ya > 0)
			{
				if (isBlocking(x + xa - width, y + ya, xa, 0)) collide = true;
				else if (isBlocking(x + xa + width, y + ya, xa, 0)) collide = true;
				else if (isBlocking(x + xa - width, y + ya + 1, xa, ya)) collide = true;
				else if (isBlocking(x + xa + width, y + ya + 1, xa, ya)) collide = true;
			}
			if (ya < 0)
			{
				if (isBlocking(x + xa, y + ya - height, xa, ya)) collide = true;
				else if (collide || isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true;
				else if (collide || isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true;
			}
			if (xa > 0)
			{
				if (isBlocking(x + xa + width, y + ya - height, xa, ya)) collide = true;
				if (isBlocking(x + xa + width, y + ya - height / 2, xa, ya)) collide = true;
				if (isBlocking(x + xa + width, y + ya, xa, ya)) collide = true;

				if (avoidCliffs && onGround && !world.level.isBlocking((int)((x + xa + width) / 16), (int)((y) / 16 + 1), xa, 1)) collide = true;
			}
			if (xa < 0)
			{
				if (isBlocking(x + xa - width, y + ya - height, xa, ya)) collide = true;
				if (isBlocking(x + xa - width, y + ya - height / 2, xa, ya)) collide = true;
				if (isBlocking(x + xa - width, y + ya, xa, ya)) collide = true;

				if (avoidCliffs && onGround && !world.level.isBlocking((int)((x + xa - width) / 16), (int)((y) / 16 + 1), xa, 1)) collide = true;
			}

			if (collide)
			{
				if (xa < 0)
				{
					x = (int)((x - width) / 16) * 16 + width;
					this.xDelta = 0;
				}
				if (xa > 0)
				{
					x = (int)((x + width) / 16 + 1) * 16 - width - 1;
					this.xDelta = 0;
				}
				if (ya < 0)
				{
					y = (int)((y - height) / 16) * 16 + height;
					this.yDelta = 0;
				}
				if (ya > 0)
				{
					y = (int)(y / 16 + 1) * 16 - 1;
					onGround = true;
				}
				return false;
			}
			else
			{
				x += xa;
				y += ya;
				return true;
			}
		}

		private bool isBlocking(double _x, double _y, double xa, double ya)
		{
			int x = (int)(_x / 16);
			int y = (int)(_y / 16);
			if (x == (int)(this.x / 16) && y == (int)(this.y / 16)) return false;

			bool blocking = world.level.isBlocking(x, y, xa, ya);

			byte block = world.level.getBlock(x, y);

			if (blocking && ya == 0 && xa != 0)
			{
				world.bump(x, y, true);
			}

			return blocking;
		}

		public override void bumpCheck(int xTile, int yTile)
		{
			if (x + width > xTile * 16 && x - width < xTile * 16 + 16 && yTile == (int)((y - 1) / 16))
			{
				facing = -world.mario.facing;
				yDelta = -10;
			}
		}

		public void die()
		{
			dead = true;

			carried = false;

			xDelta = -facing * 2;
			yDelta = -5;
			deadTime = 100;
		}

		public override bool shellCollideCheck(Shell shell)
		{
			if (deadTime != 0) return false;

			double xD = shell.x - x;
			double yD = shell.y - y;

			if (xD > -16 && xD < 16)
			{
				if (yD > -height && yD < shell.height)
				{
					world.sound.play(Art.samples[Art.SAMPLE_MARIO_KICK], this, 1, 1, 1);

					if (world.mario.carried == shell || world.mario.carried == this)
					{
						world.mario.carried = null;
					}

					die();
					shell.die();
					return true;
				}
			}
			return false;
		}


		public override void release(Mario mario)
		{
			carried = false;
			facing = mario.facing;
			x += facing * 8;
		}
	}
}